﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Windows.Media;
using WickedFlame.Core;
using WickedFlame.Core.Layers;
using WickedFlame.Core.Shapes;
using WickedFlame.Core.Extensions;

namespace WickedFlame.Util.Data
{
    public class SvgFileFormat : FileFormat
    {
        public override void Export(DrawingCanvas canvas, Stream stream)
        {
            var doc = new XmlDocument();

            XmlDeclaration decl = doc.CreateXmlDeclaration("1.0", "iso-8859-1", "");
            doc.AppendChild(decl);

            XmlComment com = doc.CreateComment("Created with VecDraw http://vecdraw.codeplex.com");
            doc.AppendChild(com);

            XmlElement rootElement = doc.CreateElement("svg");

            XmlAttribute ns = doc.CreateAttribute("xmlns:svg");
            ns.InnerText = "http://www.w3.org/2000/svg";
            rootElement.Attributes.Append(ns);

            ns = doc.CreateAttribute("xmlns");
            ns.InnerText = "http://www.w3.org/2000/svg";
            rootElement.Attributes.Append(ns);

            ns = doc.CreateAttribute("xmlns:vecdraw");
            ns.InnerText = "http://vecdraw.codeplex.com";
            rootElement.Attributes.Append(ns);

            XmlAttribute atr = doc.CreateAttribute("version");
            atr.InnerText = "1.1";
            rootElement.Attributes.Append(atr);

            atr = doc.CreateAttribute("width");
            atr.InnerText = canvas.Width.ToString();
            rootElement.Attributes.Append(atr);

            atr = doc.CreateAttribute("height");
            atr.InnerText = canvas.Height.ToString();
            rootElement.Attributes.Append(atr);

            XmlElement defs = doc.CreateElement("defs");
            rootElement.AppendChild(defs);

            foreach (Layer l in canvas.Layers)
            {
                // Layer element/group
                XmlElement le = doc.CreateElement("g");
                rootElement.AppendChild(le);

                foreach (VectorShape s in l.ShapeList)
                {
                    if (s is RectangleShape)
                        le.AppendChild(CreateNode(doc, s as RectangleShape));
                    else if (s is EllipseShape)
                        le.AppendChild(CreateNode(doc, s as EllipseShape));
                    else if (s is LineShape)
                        le.AppendChild(CreateNode(doc, s as LineShape));
                    else if (s is CurveShape)
                        le.AppendChild(CreateNode(doc, s as CurveShape));
                    else if (s is SCurveShape)
                        le.AppendChild(CreateNode(doc, s as SCurveShape));
                    else if (s is PolygonShape)
                        le.AppendChild(CreateNode(doc, s as PolygonShape));
                    else if (s is TextShape)
                        le.AppendChild(CreateNode(doc, s as TextShape));
                    else
                        throw new ShapeException("Shape " + s.GetType() + " is not jet implemented in the svg file format.");
                }
            }

            doc.AppendChild(rootElement);

            doc.Save(stream);
        }

        public override DrawingCanvas Import(Stream stream)
        {
            DrawingCanvas canvas = new DrawingCanvas();

            
            XmlDocument doc = new XmlDocument();
            doc.Load(stream);

            XmlNamespaceManager nsmngr = new XmlNamespaceManager(doc.NameTable);
            nsmngr.AddNamespace("", "http://www.w3.org/2000/svg");
            nsmngr.AddNamespace("svg", "http://www.w3.org/2000/svg");
            nsmngr.AddNamespace("vecdraw", "http://vecdraw.codeplex.com");
            //nsmngr.AddNamespace("x", doc.OwnerDocument.DocumentElement.NamespaceURI);

            //XmlNodeList testlist = doc.SelectNodes("svg");//, nsmngr);
            XmlNode root = doc.SelectSingleNode("svg", nsmngr);
            if (root == null)
                throw new CanvasException("Filedefinition is not a true svg type.\nNo svg node avaliable");

            canvas.Width = int.Parse(root.Attributes["width"].Value);
            canvas.Height = int.Parse(root.Attributes["height"].Value);

            XmlNodeList layers = root.SelectNodes("g");

            foreach (XmlNode layer in layers)
            {
                canvas.AddLayer();

                foreach (XmlNode s in layer)
                {
                    switch (s.Name)
                    {
                        case "rectangle":
                            break;
                        case "line":
                            break;
                        case "ellipse":
                            break;
                        case "path":
                            string type = "";
                            try
                            {
                                type = s.Attributes["type"].Value;
                            }
                            catch (NullReferenceException)
                            {
                                // standard svg does not contain this attribute
                                // create normal path/polygonshape
                            }

                            switch (type)
                            {
                                case "c":
                                    break;
                                case "sc":
                                    break;
                                default:
                                    break;
                            }

                            break;
                        case "text":
                            break;
                    }
                }
            }

            if (canvas.Layers == null || canvas.Layers.Count == 0)
            {
                //canvas.AddLayer();
                throw new CanvasException("No shapes avaliable to load");
            }

            //throw new NotImplementedException();
            return canvas;
        }

        private XmlNode CreateNode(XmlDocument doc, RectangleShape shape)
        {
            XmlNode node = doc.CreateElement("rect");

            XmlAttribute a = doc.CreateAttribute("width");
            a.InnerText = shape.Width.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("height");
            a.InnerText = shape.Height.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("x");
            a.InnerText = shape.X.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("y");
            a.InnerText = shape.Y.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, EllipseShape shape)
        {
            XmlNode node = doc.CreateElement("ellipse");

            XmlAttribute a = doc.CreateAttribute("cx");
            a.InnerText = (shape.X + (shape.Width / 2)).ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("cy");
            a.InnerText = (shape.Y + (shape.Height / 2)).ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("rx");
            a.InnerText = (shape.Width / 2).ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("ry");
            a.InnerText = (shape.Height / 2).ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, LineShape shape)
        {
            XmlNode node = doc.CreateElement("line");

            XmlAttribute a = doc.CreateAttribute("x1");
            a.InnerText = shape.StartPoint.X.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("y1");
            a.InnerText = shape.StartPoint.Y.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("x2");
            a.InnerText = shape.EndPoint.X.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("y2");
            a.InnerText = shape.EndPoint.Y.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, CurveShape shape)
        {
            XmlNode node = doc.CreateElement("path");

            //XmlAttribute a = doc.CreateAttribute("type","vecdraw","http://vecdraw.codeplex.com");
            XmlAttribute a = doc.CreateAttribute("vecdraw:type");
            a.InnerText = "c";
            node.Attributes.Append(a);

            a = doc.CreateAttribute("d");
            a.InnerText = shape.GeometryString;
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, SCurveShape shape)
        {
            XmlNode node = doc.CreateElement("path");

            XmlAttribute a = doc.CreateAttribute("vecdraw:type");
            a.InnerText = "sc";
            node.Attributes.Append(a);

            a = doc.CreateAttribute("d");
            a.InnerText = shape.GeometryString;
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, PolygonShape shape)
        {
            XmlNode node = doc.CreateElement("path");

            XmlAttribute a = doc.CreateAttribute("vecdraw:type");
            a.InnerText = "p";
            node.Attributes.Append(a);

            a = doc.CreateAttribute("d");
            a.InnerText = shape.GeometryString;
            node.Attributes.Append(a);

            a = doc.CreateAttribute("style");
            a.InnerText = CreateStyleString(shape);
            node.Attributes.Append(a);

            return node;
        }

        private XmlNode CreateNode(XmlDocument doc, TextShape shape)
        {
            XmlNode node = doc.CreateElement("text");

            XmlAttribute a = doc.CreateAttribute("x");
            a.InnerText = shape.Point.X.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("y");
            a.InnerText = (shape.Point.Y + shape.LineHeight).ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("font-family");
            a.InnerText = shape.FontFamily.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("font-size");
            a.InnerText = shape.FontSize.ToString();
            node.Attributes.Append(a);

            a = doc.CreateAttribute("fill");
            a.InnerText = ((SolidColorBrush)shape.Stroke).Color.ToRGBString();
            node.Attributes.Append(a);


  //          <text x="250" y="150" 
  //          font-family="Verdana" font-size="55" fill="blue" >
  //          Hello, out there
  //          </text>

         //   <tspan
         //x="125.71429"
         //y="512.36218"
         //id="tspan2818">sdfgsdfgsdfgs</tspan><tspan
         //x="125.71429"
         //y="562.36218"
         //id="tspan2820">dfg</tspan>

            if (shape.Text.LastIndexOf('\r') <= 0)
            {
                // Single line
                node.InnerText = shape.Text;
            }
            else
            {
                // multyple lines
                string[] lines = shape.Text.Split('\r');

                for (int i = 0; i < lines.Length; i++)
                {
                    XmlNode tn = doc.CreateElement("tspan");

                    XmlAttribute ta = doc.CreateAttribute("x");
                    ta.InnerText = shape.Point.X.ToString();
                    tn.Attributes.Append(ta);

                    ta = doc.CreateAttribute("y");
                    ta.InnerText = (shape.Point.Y + shape.LineHeight + (i * shape.LineHeight)).ToString();
                    tn.Attributes.Append(ta);

                    tn.InnerText = lines[i];

                    node.AppendChild(tn);
                }
            }

            return node;
        }

        private string CreateStyleString(VectorShape shape)
        {
            string style = "";

            double a = (100.00 / 255.00 * ((SolidColorBrush)shape.Fill).Color.A) / 100;
            style += "fill:" + ((SolidColorBrush)shape.Fill).Color.ToRGBString();
            style += ";fill-opacity:" + a;

            a = (100.00 / 255.00 * ((SolidColorBrush)shape.Stroke).Color.A) / 100;
            style += ";stroke:" + ((SolidColorBrush)shape.Stroke).Color.ToRGBString();
            style += ";stroke-width:" + shape.StrokeThickness.ToString();
            style += ";stroke-opacity:" + a;

            return style;
        }

        private void ReadStyle(string styleString)
        {
            //style="stroke:rgb(99,99,99);stroke-width:2"/>

            //style="fill:white;stroke:red;stroke-width:2"/>

            //;stroke-miterlimit:4;stroke-dasharray:none
        }
    }
}
